package tk.mybatis.springboot.ping;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.X509EncodedKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class WebhooksVerifyExample {
	protected static final Logger LOG = LogManager.getLogger(WebhooksVerifyExample.class);
	private static String pubKeyPath;

    public static boolean runDemos(String webhooksRawPostData, String signature){
    	URL url= Ping.class.getResource("/pingpp_public_key.pem");
    	pubKeyPath = url.toString();
    	pubKeyPath = pubKeyPath.replace("file:/", "");
    	try{
    		pubKeyPath = URLDecoder.decode(pubKeyPath, "utf-8");
	    	if(!System.getProperty("os.name").toLowerCase().startsWith("win")){
	    		pubKeyPath = "/"+URLDecoder.decode(pubKeyPath, "utf-8");
	    	}
    		return verifyData(webhooksRawPostData, signature, getPubKey());
        }catch(UnsupportedEncodingException e){
        	LOG.error(e.getMessage(),e);
        } catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
        	LOG.error(e.getMessage(),e);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			LOG.error(e.getMessage(),e);
		} catch (SignatureException e) {
			// TODO Auto-generated catch block
			LOG.error(e.getMessage());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			LOG.error(e.getMessage(),e);
		}
    	return false;
    }

    /**
     * 读取文件, 部署 web 程序的时候, 签名和验签内容需要从 request 中获得
     * @param filePath
     * @return
     * @throws Exception
     */
    public static String getStringFromFile(String filePath) throws Exception {
        FileInputStream in = new FileInputStream(filePath);
        InputStreamReader inReader = new InputStreamReader(in, "UTF-8");
        BufferedReader bf = new BufferedReader(inReader);
        StringBuilder sb = new StringBuilder();
        String line;
        do {
            line = bf.readLine();
            if (line != null) {
                if (sb.length() != 0) {
                    sb.append("\n");
                }
                sb.append(line);
            }
        } while (line != null);

        return sb.toString();
    }

	/**
	 * 获得公钥
	 * @return
	 * @throws Exception
	 */
	public static PublicKey getPubKey() throws Exception {
//		String pubKeyString = getStringFromFile(pubKeyPath);
		String pubKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw10MbWY5GAldBr3ZvwQ9\n" +
				"iW4B50f1dTDummVAYVLUPzK0TdbfXUm+ODpTAlJxhyMc1B7tGRG9XSYOmgzkazr4\n" +
				"rU+Tbs2GFTArir3RQHk5vs9XLkSnAE8slRHQvzWDxaB7iuk+TQEeoFLOu7SBVtWr\n" +
				"Rff5dNmihYalvTIFGVCiE2bUDQ4DF0SG4Tuo1RyilTaPCh4GOrB+m5z7n8+ApXVp\n" +
				"ngiYMbgFOzNU8OLv5jlmk/p9MBikH0g7yTQxzAfFS10avSkFjdqHETtdYCRwCA6b\n" +
				"B+DJZVo4O11SSInGqjAFQv01H33HMlOXw9hmyhpaf4aThYQkyxOEOfgOw18V9cIH\n" +
				"6QIDAQAB";
//        pubKeyString = pubKeyString.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
        byte[] keyBytes = Base64.decodeBase64(pubKeyString);

		// generate public key
		X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(spec);
		return publicKey;
	}

	/**
	 * 验证签名
	 * @param dataString
	 * @param signatureString
	 * @param publicKey
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 * @throws SignatureException
	 */
	public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey)
            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
        byte[] signatureBytes = Base64.decodeBase64(signatureString);
        Signature signature = Signature.getInstance("SHA256withRSA");
		signature.initVerify(publicKey);
		signature.update(dataString.getBytes("UTF-8"));
		return signature.verify(signatureBytes);
	}

}
